package websocket;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;
import po.Message;
import service.LoginService;

import java.io.IOException;
import java.util.Date;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Socket处理器
 */
@Component
public class MyWebSocketHandler implements WebSocketHandler {
	/**
	 * -2表示下线消息
	 */
	private static final Long OFFLINE = -2L;
	/**
	 * 0表示上线消息
	 */
	private static final Long ONLINE = 0L;

	/**
	 * 用于保存HttpSession与WebSocketSession的映射关系
	 */
	public static final Map<Long, WebSocketSession> userSocketSessionMap;

	@Autowired
	private LoginService loginservice;
	
	static {
		userSocketSessionMap = new ConcurrentHashMap<>();
	}

	/**
	 * 建立连接后,把登录用户的id写入WebSocketSession
	 * @param session
	 * @throws Exception
	 */
	public void afterConnectionEstablished(WebSocketSession session) throws Exception {
		Long uid = (Long) session.getAttributes().get("uid");
		String username=loginservice.getNameById(uid);
		if (userSocketSessionMap.get(uid) == null) {
			userSocketSessionMap.put(uid, session);
			Message msg = new Message();
			msg.setFrom(ONLINE);
			msg.setText(username);
			String payload = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create().toJson(msg);
			this.broadcast(new TextMessage(payload));
		}
	}

	/**
	 * 消息处理，在客户端通过Websocket API发送的消息会经过这里，然后进行相应的处理
	 * @param session
	 * @param message
	 * @throws Exception
	 */
	public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
		if (message.getPayloadLength() == 0) {
			return;
		}
		Message msg = new Gson().fromJson(message.getPayload().toString(), Message.class);
		msg.setDate(new Date());
		String payload = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create().toJson(msg);
		sendMessageToUser(msg.getTo(), new TextMessage(payload));
	}

	/**
	 * 消息传输错误处理
	 * @param session
	 * @param exception
	 * @throws Exception
	 */
	public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
		if (session.isOpen()) {
			session.close();
		}
		// 移除当前抛出异常用户的Socket会话
		for (Entry<Long, WebSocketSession> entry : userSocketSessionMap.entrySet()) {
			if (entry.getValue().getId().equals(session.getId())) {
				userSocketSessionMap.remove(entry.getKey());
				System.out.println("Socket会话已经移除:用户ID" + entry.getKey());
				String username = loginservice.getNameById(entry.getKey());
				Message msg = new Message();
				msg.setFrom(OFFLINE);
				msg.setText(username);
				String payload = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create().toJson(msg);
				this.broadcast(new TextMessage(payload));
				break;
			}
		}
	}

	/**
	 * 关闭连接后
	 * @param session
	 * @param closeStatus
	 * @throws Exception
	 */
	public void afterConnectionClosed(WebSocketSession session,CloseStatus closeStatus) throws Exception {
		System.out.println("Websocket:" + session.getId() + "已经关闭");
		// 移除当前用户的Socket会话
		for (Entry<Long, WebSocketSession> entry : userSocketSessionMap.entrySet()) {
			if (entry.getValue().getId().equals(session.getId())) {
				userSocketSessionMap.remove(entry.getKey());
				System.out.println("Socket会话已经移除:用户ID" + entry.getKey());
				String username = loginservice.getNameById(entry.getKey());
				Message msg = new Message();
				msg.setFrom(OFFLINE);
				msg.setText(username);
				String payload = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create().toJson(msg);
				this.broadcast(new TextMessage(payload));
				break;
			}
		}
	}

	public boolean supportsPartialMessages() {
		return false;
	}

	/**
	 * 给所有在线用户发送消息
	 * @param message
	 * @throws IOException
	 */
	public void broadcast(final TextMessage message) throws IOException {
		//多线程群发
		for (Entry<Long, WebSocketSession> entry : userSocketSessionMap.entrySet()) {
			if (entry.getValue().isOpen()) {
				// entry.getValue().sendMessage(message);
				new Thread(() -> {
					try {
						if (entry.getValue().isOpen()) {
							entry.getValue().sendMessage(message);
						}
					} catch (IOException e) {
						e.printStackTrace();
					}
				}).start();
			}

		}
	}

	/**
	 * 给某个用户发送消息
	 * 
	 * @param uid
	 * @param message
	 * @throws IOException
	 */
	public void sendMessageToUser(Long uid, TextMessage message) throws IOException {
		WebSocketSession session = userSocketSessionMap.get(uid);
		if (session != null && session.isOpen()) {
			session.sendMessage(message);
		}
	}

}
